<?php
/**
 * caching loader
 *
 * @author alex_ez
 */

class cache extends singleton implements cacher_interface
{
	static public function &instance() { return parent::instance(__CLASS__); }

	protected $conf = array();
	protected $storage = array();
	protected $enabled = true;
	protected $enables = array();

	protected $ttl = null;
	protected $cacher = null;

	protected function __construct() {
		$this->conf = config::instance()->cache;
		$this->enabled = $this->conf['enabled'];
		
		$driver = $this->conf['driver'] = (isset($this->conf['driver'])?$this->conf['driver']:null);
		if(empty($driver))
			$driver = (is_callable('apc_store')?'apc':
				(is_callable('eaccelerator_get')?'eaccelerator':
				(class_exists('memcached')?'mem':'file')));
		$cacher = 'cacher_' . $driver;
		$this->cacher = new $cacher();
		
		$this->ttl(isset($this->conf['ttl'])?$this->conf['ttl']:'1M');
	}
	
	public function on() { return !$this->off(); }
	public function off() {
		if( $this->enabled == 0 ) return true;

		if( $this->conf['enabled']<0 )
			return true;

		end($this->enables);
		$k = key($this->enables);
		if(isset($this->conf[$k]))
			return $this->conf[$k]&&$this->conf['enabled'];

		//if( $this ->enabled == -1 && !defined('QFOX_PAGE_DRAWING') ) return true;
		return false;
	}

	public function enable($k = null, $ttl = null) {
		if(!is_null($k)&&!isset($this ->enables[$k]))
			$this->enables[$k] = $this ->enabled;

		if(!is_null($ttl))
			$this->ttl($ttl);

		$this->enabled = 1;
		return $this;
	}

	public function disable($k = null)
	{
		if (!is_null($k)&&isset($this->enables[$k])) {
			$this->enabled = $this->enables[$k];
			unset($this->enables[$k]);
			if(!empty($this->enables)) return $this;;
		}

		$this->enabled = 0;
		$this->enables = array();
		return $this;
	}

	// cacher interface
	public function key($class,$method,$params=null) {
		return $class . '/' . $method . '/' . (empty($params)?'index':md5($this->pack_params($params)));
	}

	public function store($key,&$value,$ttl=null)
	{
		if($this->off()) return false;

		return $this->cacher->store($key,$value,$this->ttl($ttl));
	}

	public function retrieve($key)
	{
		if($this ->off()) return false;

		return $this->cacher->retrieve($key);
	}

	public function __get($k) { return $this->retrieve($k); }
	public function __set($k,$v) { return $this->store($k,$v,$this->ttl); }

	public function drop($key)
	{
		return $this->cacher->drop($key);
	}

	public function cleanup()
	{
		return $this->cacher->cleanup();
	}

	public function info()
	{
		return $this->cacher->info();
	}
	

	// tools
	public function ttl( $ttl = null )
	{
		if( !empty($ttl) )
		{
			list( $c, $u ) = sscanf( $ttl, '%u%c' ); // $count and $unit
			$u = strtolower( $u );
			$u2m = array( 'm' => 60, 'h' => 3600, 'd' => 3600*24, 'w' => 3600*24*7 ); // unit2multiplier
			$this->ttl = (int)(isset($u2m[$u])?($c*$u2m[$u]):$c);
		}
		
		return $this->ttl;
	}
	
	protected function pack_params(&$p)
	{
		if ($this->off()) return;

		if(is_scalar($p)) return is_numeric($p)?(is_int($p)?intval($p):floatval($p)):trim($p);
		if(is_object($p)) return json_encode($p);
		if(!is_array($p)) return var_export($p,1);

		ksort($p);
		return json_encode($p);
	}
	
	protected function cache_name(&$class, &$method, $params)
	{
	}
}

